package com.nl.web.utils;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * WebUtils.
 *
 * @author breggor
 */
@Slf4j
@UtilityClass
public class WebUC {

    public static final String USER_AGENT_HEADER = "user-agent";

    public static final String UN_KNOWN = "unknown";

    private static final String BODY_ATTR_KEY = "REQUEST_BODY";

    /**
     * 获取Annotation.
     *
     * @param handlerMethod  HandlerMethod
     * @param annotationType 注解类
     * @param <A>            泛型标记
     * @return {Annotation}
     */
    public static <A extends Annotation> A getAnnotation(final HandlerMethod handlerMethod, final Class<A> annotationType) {
        // 先找方法，再找方法上的类
        A annotation = handlerMethod.getMethodAnnotation(annotationType);
        if (null != annotation) {
            return annotation;
        }
        // 获取类上面的Annotation，可能包含组合注解，故采用spring的工具类
        Class<?> beanType = handlerMethod.getBeanType();
        return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
    }

    /**
     * 判断是否ajax请求.
     * spring ajax 返回含有 ResponseBody 或者 RestController注解
     *
     * @param handlerMethod HandlerMethod
     * @return 是否ajax请求
     */
    public static boolean isBody(final HandlerMethod handlerMethod) {
        ResponseBody responseBody = getAnnotation(handlerMethod, ResponseBody.class);
        return responseBody != null;
    }

    /**
     * 读取cookie.
     *
     * @param name cookie name
     * @return cookie value
     */
    @Nullable
    public static String getCookieVal(final String name) {
        HttpServletRequest request = getRequest();
        Assert.notNull(request, "request from RequestContextHolder is null");
        return getCookieVal(request, name);
    }

    /**
     * 读取cookie.
     *
     * @param request HttpServletRequest
     * @param name    cookie name
     * @return cookie value
     */
    @Nullable
    public static String getCookieVal(final HttpServletRequest request, final String name) {
        Cookie cookie = WebUtils.getCookie(request, name);
        return cookie != null ? cookie.getValue() : null;
    }

    /**
     * 清除 某个指定的cookie.
     *
     * @param response HttpServletResponse
     * @param key      cookie key
     */
    public static void removeCookie(final HttpServletResponse response, final String key) {
        setCookie(response, key, null, 0);
    }

    /**
     * 设置cookie.
     *
     * @param response        HttpServletResponse
     * @param name            cookie name
     * @param value           cookie value
     * @param maxAgeInSeconds maxage
     */
    public static void setCookie(final HttpServletResponse response, final String name, final @Nullable String value, final int maxAgeInSeconds) {
        Cookie cookie = new Cookie(name, value);
        cookie.setPath("/");
        cookie.setMaxAge(maxAgeInSeconds);
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
    }

    /**
     * 获取 HttpServletRequest.
     *
     * @return {HttpServletRequest}
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return (requestAttributes != null) ? ((ServletRequestAttributes) requestAttributes).getRequest() : null;
    }

    /**
     * 获取 request 请求的 byte[] 数组.
     *
     * @param request request
     * @return byte[]
     * @throws IOException IOException
     */
    public static byte[] getRequestBytes(final HttpServletRequest request) throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
            return null;
        }
        byte[] buffer = new byte[contentLength];
        for (int i = 0; i < contentLength; ) {

            int readlen = request.getInputStream().read(buffer, i, contentLength - i);
            if (readlen == -1) {
                break;
            }
            i += readlen;
        }
        return buffer;
    }

    /**
     * 获取http header信息.
     *
     * @param name name
     * @return String
     */
    public static String getHeader(final String name) {
        String result = null;
        if (getRequest() != null) {
            result = getRequest().getHeader(name);
        }
        return result;
    }

    /**
     * getHeaders.
     *
     * @return Map
     */
    public static Map<String, String> getHeaders() {
        Map<String, String> headerMap = new HashMap<>(16);
        Enumeration enums = getRequest().getHeaderNames();
        while (enums.hasMoreElements()) {
            String name = (String) enums.nextElement();
            String value = getHeader(name);
            if (null != value && !"".equals(value)) {
                headerMap.put(name, value);
            }
        }
        return headerMap;
    }

    /**
     * 获取String参数.
     *
     * @param name name
     * @return String
     */
    public static String getParameter(final String name) {
        return getRequest() != null ? getRequest().getParameter(name) : null;
    }

    /**
     * 获取String参数.
     *
     * @param name         name
     * @param defaultValue default value
     * @return string
     */
    public static String getParameter(final String name, final String defaultValue) {

        return Objects.toString(getRequest() != null ? getRequest().getParameter(name) : null, defaultValue);
    }

    /**
     * 获取Integer参数.
     *
     * @param name name
     * @return Integer
     */
    public static Integer getParameterToInt(final String name) {
        return getParameterToInt(name, null);
    }

    /**
     * 获取Integer参数.
     *
     * @param name         name
     * @param defaultValue default value
     * @return Integer
     */
    public static Integer getParameterToInt(final String name, final Integer defaultValue) {
        HttpServletRequest request = getRequest();
        return  request != null ?
            (request.getParameter(name)==null? null: Integer.parseInt(request.getParameter(name))) : null;
    }

    /**
     * 获取response.
     *
     * @return HttpServletResponse
     */
    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
    }


    /**
     * 获取请求属性.
     *
     * @return ServletRequestAttributes
     */
    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }


}
